package lt.marsrutai.mobile.android.fragment;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lt.marsrutai.mobile.android.AppContext;
import lt.marsrutai.mobile.android.R;
import lt.marsrutai.mobile.android.activity.intent.NearestRoutesIntentHolder;
import lt.marsrutai.mobile.android.activity.intent.StopTimesIntentHolder;
import lt.marsrutai.mobile.android.adapter.StopBookmarkAdapter;
import lt.marsrutai.mobile.android.exception.DataAccessException;
import lt.marsrutai.mobile.android.exception.UnableAccessDataException;
import lt.marsrutai.mobile.android.manager.ActivityManager;
import lt.marsrutai.mobile.android.model.ArrivalTime;
import lt.marsrutai.mobile.android.model.MobileScope;
import lt.marsrutai.mobile.android.model.Schedule;
import lt.marsrutai.mobile.android.model.Stop;
import lt.marsrutai.mobile.android.model.StopArrivalTimes;
import lt.marsrutai.mobile.android.model.StopBookmark;
import lt.marsrutai.mobile.android.model.Track;
import lt.marsrutai.mobile.android.model.enums.DateTime;
import lt.marsrutai.mobile.android.model.enums.WeekdayType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.actionbarsherlock.app.SherlockListFragment;

public class StopBookmarksFragment extends SherlockListFragment {

    private static final Logger logger = LoggerFactory.getLogger("StopBookmarksFragment");

    private ActivityManager manager;

    private List<StopBookmark> stopBookmarks;

    private Map<StopBookmark, MobileScope> mobileScopes;
    private Map<StopBookmark, Stop> stops;
    private Map<StopBookmark, Schedule> schedules;
    private Map<StopBookmark, List<ArrivalTime>> stopTimes;

    private ArrayAdapter<StopBookmark> adapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.list_fragment, null);
        ((TextView) view.findViewById(android.R.id.empty)).setText(R.string.stop_bookmarks_not_found);
        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        registerForContextMenu(getListView());
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        if (null == manager) {
            manager = new ActivityManager(getActivity());
        }

        if (null == adapter) {
            downloadData();
        }
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        sendStopData(stopBookmarks.get(position));
    }

    public void downloadData() {
        Runnable downloadTask = new Runnable() {

            @Override
            public void run() {
                getBookmarkedStops();
            }
        };
        Thread thread = new Thread(downloadTask);
        thread.start();

        manager.showDownloadLoadingBar();
    }

    private void getBookmarkedStops() {
        try {
            Set<StopBookmark> storedStopBookmarks = AppContext.getBookmarkService().getStopBookmarks();
            int storedBookmarksCount = storedStopBookmarks.size();

            stopBookmarks = new ArrayList<StopBookmark>(storedBookmarksCount);

            // consider default hashmap load factor
            int hashMapSize = (int) (storedBookmarksCount / 0.75);

            mobileScopes = new HashMap<StopBookmark, MobileScope>(hashMapSize);
            stops = new HashMap<StopBookmark, Stop>(hashMapSize);
            schedules = new HashMap<StopBookmark, Schedule>(hashMapSize);
            stopTimes = new HashMap<StopBookmark, List<ArrivalTime>>(hashMapSize);

            for (StopBookmark stopBookmark : storedStopBookmarks) {
                try {
                    MobileScope mobileScope = AppContext.getDataService().getScopeInfo(stopBookmark.getScope());
                    Stop stop = AppContext.getDataService().getStopById(stopBookmark.getScope(),
                            stopBookmark.getStopId());
                    Track track = AppContext.getDataService().getTrackById(stopBookmark.getScope(),
                            stopBookmark.getTrackId());
                    Schedule schedule = AppContext.getDataService().getScheduleById(stopBookmark.getScope(),
                            track.getScheduleId());
                    StopArrivalTimes trackStopTimes = AppContext.getDataService().getStopTimes(
                            stopBookmark.getScope(), track.getScheduleId(), stopBookmark.getTrackId(),
                            stopBookmark.getStopId());
                    List<ArrivalTime> arrivalTimes = trackStopTimes.getArrivalTimes(WeekdayType.parseEnumSunSat(new DateTime().getWeekDay()));

                    mobileScopes.put(stopBookmark, mobileScope);
                    stops.put(stopBookmark, stop);
                    schedules.put(stopBookmark, schedule);
                    stopTimes.put(stopBookmark, arrivalTimes);
                    stopBookmarks.add(stopBookmark);
                }
                catch (UnableAccessDataException ex) {
                    logger.info(String.format("Unable to access data for scope: %s, trackId: %s, stopId: %s.",
                            stopBookmark.getScope(), stopBookmark.getTrackId(), stopBookmark.getStopId()));
                    // TODO: delete invalid bookmarks
                    // ex. stops that no longer exist
                }
            }
        }
        catch (DataAccessException e) {
            manager.runOnUiThread(manager.errorRes);
            return;
        }
        manager.runOnUiThread(returnRes);
    }

    private Runnable returnRes = new Runnable() {

        @Override
        public void run() {

            adapter = new StopBookmarkAdapter(getActivity(), stops, schedules, stopTimes);
            setListAdapter(adapter);

            if (stopBookmarks != null && stopBookmarks.size() > 0) {
                for (int i = 0; i < stopBookmarks.size(); i++) {
                    adapter.add(stopBookmarks.get(i));
                }
            }
            manager.dismissDownloadLoadingBar();
        }
    };

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater inflater = getActivity().getMenuInflater();
        inflater.inflate(R.menu.stop_bookmark_context_menu, menu);
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        // full class path so it does not get confused with actionbarsherlock class
        android.widget.AdapterView.AdapterContextMenuInfo info = (android.widget.AdapterView.AdapterContextMenuInfo) item
                .getMenuInfo();

        StopBookmark stopBookmark = stopBookmarks.get((int) info.id);
        Stop stop = stops.get(stopBookmark);

        switch (item.getItemId()) {
        case R.id.next_schedules:
            NearestRoutesIntentHolder intentHolder = new NearestRoutesIntentHolder(getActivity());
            intentHolder.setScopeFolder(stopBookmark.getScope());
            intentHolder.setStopName(stop.getName());
            startActivity(intentHolder.getIntent());
            return true;
        case R.id.remove_bookmark:
            AppContext.getBookmarkService().removeStopBookmark(stopBookmark);
            adapter.remove(stopBookmark);
            return true;
        default:
            return super.onContextItemSelected(item);
        }
    }

    public void sendStopData(StopBookmark stopBookmark) {
        MobileScope mobileScope = mobileScopes.get(stopBookmark);
        Stop stop = stops.get(stopBookmark);
        Schedule schedule = schedules.get(stopBookmark);

        StopTimesIntentHolder intentHolder = new StopTimesIntentHolder(getActivity());
        intentHolder.setScopeFolder(mobileScope.getFolder());
        intentHolder.setScopeName(mobileScope.getName());
        intentHolder.setTransportId(schedule.getTransportId());
        intentHolder.setScheduleId(schedule.getId());
        intentHolder.setScheduleName(schedule.getName());
        intentHolder.setScheduleTrackName(schedule.getTrackName());
        intentHolder.setTrackId(stopBookmark.getTrackId());
        intentHolder.setTrackName(schedule.getTrackName());
        intentHolder.setStopId(stopBookmark.getStopId());
        intentHolder.setStopName(stop.getName());
        intentHolder.setStopDirectionName(stop.getDirectionName());
        startActivity(intentHolder.getIntent());
    }

}
